#include "modbus_serial_port.h"

#include <chrono>
#include <iostream>
#include <thread>

#include "tools.h"
// 父类实现---------------------------------------------------------------------------------

ModbusBase::ModbusBase(SerialPort& serial, int timeout_ms,
                       size_t max_buffer_size, uint8_t slave_addr)
    : m_serial_(serial), m_timeout_ms_(timeout_ms),
      m_max_buffer_size_(max_buffer_size), m_slave_addr_(slave_addr) {
  m_rx_buffer_.reserve(m_max_buffer_size_);
  m_pending_buffer_.reserve(m_max_buffer_size_);
}

ModbusBase::~ModbusBase() {}

std::vector<uint8_t> ModbusBase::ReadCompleteFrame() {
  auto start_time = std::chrono::steady_clock::now();  // 获取现在的时间
  auto last_time = start_time;
  while (true) {
    auto current_time = std::chrono::steady_clock::now();  // 获取当前时间
    auto elapsed_time = std::chrono::duration_cast<std::chrono::milliseconds>(
        current_time - start_time);  // 获取已经过去的时间
    // 检测是否超时
    if (elapsed_time.count() > m_timeout_ms_) {
      return {};
    }
    // 待改进，使用epoll监控可读事件...
    // 进行接收数据包
    std::vector<uint8_t> data(1024);
    ssize_t recv_size = m_serial_.Read(data.data(), data.size());
    // 判断是否成功接收到数据
    if (recv_size > 0) {
      // 将新数据添加到缓冲区中（可能第一次只读取到了一半数据）
      m_rx_buffer_.insert(m_rx_buffer_.end(), data.begin(), data.end());
      if (m_pending_buffer_.empty()) {
        m_pending_buffer_ = m_rx_buffer_;
      } else {
        m_pending_buffer_.insert(m_pending_buffer_.end(), m_rx_buffer_.begin(),
                                 m_rx_buffer_.end());
      }
      m_rx_buffer_.clear();
      // 进行获取一条完整数据帧
      std::vector<uint8_t> result = ExtractCompleteFrame();
      if (!result.empty()) {
        return result;
      }
    } else if (recv_size == 0) {
      std::this_thread::sleep_for(
          std::chrono::milliseconds(1000));  // 睡眠10毫秒
      continue;
    } else {
      // 读取错误
      std::cout << "ReadCompleteFrame: 串口读取错误（recv_size = " << recv_size
                << "）" << std::endl;
      return {};
    }
  }
}

std::vector<uint8_t> ModbusBase::ExtractCompleteFrame() {
  std::vector<uint8_t> result;
  size_t frame_len = CheckCompleteFrame(m_pending_buffer_);
  if (frame_len > 0) {
    // 获取到一条完整数据帧,长度为frame_len
    result = std::vector<uint8_t>(m_pending_buffer_.begin(),
                                  m_pending_buffer_.begin() + frame_len);
    // 删除已经获取到的数据
    m_pending_buffer_.erase(m_pending_buffer_.begin(),
                            m_pending_buffer_.begin() + frame_len);
  }
  return result;
}

// 主站实现------------------------------------------------------------------------------

// 主站构造函数
ModbusMaster::ModbusMaster(SerialPort& serial, int timeout_ms,
                           size_t max_buffer_size)
    : ModbusBase(serial, timeout_ms, max_buffer_size)  // 调用基类构造函数
{}

size_t ModbusMaster::CheckCompleteFrame(const std::vector<uint8_t>& buffer) {
  if (buffer.size() < 4) {
    // std::cout<<"数据帧不完整"<<std::endl;
    return 0;
  }
  if(buffer[0] != m_slave_addr_) {
    return 0;
  }
  uint8_t fun_code = buffer[1];
  //  检查异常响应
  if (fun_code & 0x80) {
    // 异常响应固定5字节
    if (buffer.size() >= 5 && Tools::CheckCRC(buffer, 5)) {
      return 5;
    }
    return 0;
  }
  uint8_t fun_code = buffer[1];
  if (fun_code == ReadHoldingRegs) {
    if (buffer.size() < 5)
      return 0;  // 地址(1) + 功能码(1) + 数据大小(1) + 数据(n) + 校验码(2)
    uint8_t data_length = buffer[2];
    size_t total = 1 + 1 + 1 + data_length + 2;
    // 对该数据帧进行校验，校验成功返回整个数据报的长度
    if (total <= buffer.size() && Tools::CheckCRC(buffer, total)) {
      return total;
    }
  }
  return 0;
}

std::vector<uint8_t> ModbusMaster::GenerateMasterRequest(uint8_t slave_addr,
                                                         uint8_t fun_code,
                                                         uint16_t start_addr,
                                                         uint16_t count) {
  std::vector<uint8_t> request;
  request.push_back(slave_addr);
  request.push_back(fun_code);
  request.push_back((start_addr >> 8) & 0xFF);
  request.push_back(start_addr & 0xFF);
  request.push_back(count >> 8);
  request.push_back(count & 0xFF);
  // 获取校验码
  uint16_t verify_code = Tools::CalculateCRC(request.data(), request.size());

  request.push_back(verify_code & 0xFF);
  request.push_back((verify_code >> 8) & 0xFF);

  return request;
}

bool ModbusMaster::ParseMasterResponse(const std::vector<uint8_t>& response,
                                       uint8_t fun_code) {
  // 基础合法性检查
  if (response.size() < 5) {  // 最小响应帧：地址1+功能码1+数据长度1+CRC2
    // std::cerr << "主站：响应帧过短" << std::endl;
    return false;
  }
  if (!Tools::CheckCRC(response, response.size())) {  // CRC校验失败
    std::cerr << "主站：响应CRC错误" << std::endl;
    return false;
  }
  // 检查从站是否返回异常
  if (response[1] == (fun_code | 0x80)) {
    uint8_t err_code =
        response[2];  // Modbus异常码（01=非法功能，02=非法地址等）
    std::cerr << "主站：从站异常，错误码=0x" << std::hex << (int)err_code
              << std::dec << std::endl;
    return false;
  }
  if (response[1] != fun_code) {  // 功能码不匹配
    std::cerr << "主站：响应功能码不匹配" << std::endl;
    return false;
  }
  return true;
}

void ModbusMaster::Start() {
  // 1.生成请求帧
  std::vector<uint8_t> request =
      GenerateMasterRequest(0x01, 0x03, 0x0000, 0x000A);
  // 2.进行发送
  while (true) {
    ssize_t send_len = m_serial_.Write(request.data(), request.size());
    if (send_len != request.size()) {
      std::cout << "请求发送失败，实际发送" << send_len << "字节数据"
                << std::endl;
      std::this_thread::sleep_for(std::chrono::milliseconds(100));
      std::cout << "重新进行发送" << std::endl;
    } else {
      // 发送成功
      std::cout << "请求已发送，等待从站响应" << std::endl;
      std::this_thread::sleep_for(std::chrono::milliseconds(50));
      auto start_time = std::chrono::steady_clock::now();
      std::vector<uint8_t> response;
      // 接收响应并将响应提取
      // 给响应一定的时间到达，但设置超时
      while (std::chrono::duration_cast<std::chrono::milliseconds>(
                 std::chrono::steady_clock::now() - start_time)
                 .count() < 500) {  // 500ms超时
        response = ReadCompleteFrame();
        if (!response.empty())
          break;
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
      }
      if (!response.empty() && ParseMasterResponse(response, ReadHoldingRegs)) {
        std::cout << "收到响应如下" << std::endl;
        Tools::PrintData(response);
      } else {
        std::cout << "未收到有效响应" << std::endl;
      }
      std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    }
  }
}

// 从站实现------------------------------------------------------------------------------

ModbusSlave::ModbusSlave(SerialPort& serial, int timeout_ms,
                         size_t max_buffer_size)
    : ModbusBase(serial, timeout_ms, max_buffer_size)  // 调用基类构造函数
{}

size_t ModbusSlave::CheckCompleteFrame(const std::vector<uint8_t>& buffer) {
  if (buffer.size() < 4) {
    return 0;
  }
  uint8_t addr = buffer[0];
  if (m_slave_addr_ != addr)  // 判断是否发给自己
  {
    return 0;
  }
  uint8_t fun_code = buffer[1];
  size_t total = 0;
  if (fun_code == ReadHoldingRegs) {
    total = 8;
  }
  std::vector<uint8_t> ret(buffer.begin(), buffer.begin() + 8);
  if (buffer.size() >= total && Tools::CheckCRC(ret, ret.size())) {
    return total;
  }
  return 0;
}

std::vector<uint8_t> ModbusSlave::GenerateSlaveResponse(
    const std::vector<uint8_t>& request) {
  if (request.size() < 8) {
    std::cout << "请求数据报不完整" << std::endl;
    return {};
  }
  std::vector<uint8_t> response;
  uint8_t device_addr = request[0];                 // 从机地址
  uint8_t func_code = request[1];                   // 功能码
  uint16_t count = (request[4] << 8 | request[5]);  // 寄存器个数

  if (func_code == 0x03 || func_code == 0x04) {
    response.push_back(device_addr);
    response.push_back(func_code);
    response.push_back(count * 2);

    // 填充0号寄存器数值
    for (int i = 0; i < count; i++) {
      response.push_back((i >> 8) & 0xFF);  // 寄存器高字节
      response.push_back(i & 0xFF);         // 寄存器低字节
    }

    // 填充校验码
    uint16_t check_code = Tools::CalculateCRC(response.data(), response.size());
    response.push_back(check_code & 0xFF);         // 低字节
    response.push_back((check_code >> 8) & 0xFF);  // 高字节
  }
  return response;
}

bool ModbusSlave::ParseSlaveRequest(const std::vector<uint8_t>& request,
                                    uint8_t& device_addr, uint8_t& func_code,
                                    uint16_t& start_addr, uint16_t& count) {
  if (request.size() < 8) {
    std::cout << "请求不完整" << std::endl;
    return false;
  }
  // 检查校验码
  if (!Tools::CheckCRC(request, request.size())) {
    std::cout << "数据不准确" << std::endl;
    return false;
  }
  device_addr = request[0];                     // 从机地址
  func_code = request[1];                       // 功能码
  start_addr = (request[2] << 8 | request[3]);  // 寄存器地址
  count = (request[4] << 8 | request[5]);       // 寄存器数量
  return true;
}

void ModbusSlave::Start() {
  while (true) {
    // 读取完整请求帧
    std::vector<uint8_t> request = ReadCompleteFrame();
    if (request.empty()) {
      std::this_thread::sleep_for(std::chrono::milliseconds(100));
      continue;
    }
    // 解析请求
    uint8_t device_addr, func_code;
    uint16_t start_addr, count;
    if (!ParseSlaveRequest(request, device_addr, func_code, start_addr,
                           count)) {
      std::cerr << "请求解析失败" << std::endl;
      continue;
    }
    // 检查地址是否匹配（从站只处理目标地址为本机的请求）
    if (device_addr != m_slave_addr_) {
      std::cout << "请求地址不匹配（目标：0x" << std::hex << (int)device_addr
                << "，本机：0x" << (int)m_slave_addr_ << std::dec << "），忽略"
                << std::endl;
      continue;
    }
    // 生成响应并发送
    std::vector<uint8_t> response = GenerateSlaveResponse(request);
    if (response.empty()) {
      std::cerr << "生成响应失败" << std::endl;
      continue;
    }

    std::cout << "发送响应：";
    for (uint8_t b : response)
      printf("%02X ", b);
    std::cout << std::endl;

    ssize_t sent = m_serial_.Write(response.data(), response.size());
    if (sent > 0) {
      std::cout << "响应发送成功（" << sent << "字节）" << std::endl;
    } else {
      std::cerr << "响应发送失败" << std::endl;
    }
  }
}